#pragma once
extern "C" {
#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libavutil/pixdesc.h"
}
#include "spdlog/spdlog.h"
#include <string>
#include "atomicops.h"
#include "readerwritercircularbuffer.h"
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <list>
struct VData {
	uint8_t * buf;
	int w, h;
	VData(int w,int h) {
		buf = new uint8_t[w * h * 3];
		this->w = w;
		this->h = h;
	}
	void Close() {
		delete[]buf;
		buf = nullptr;
	}
	~VData() {
		if(buf) delete[]buf;
	}
};

struct MemPool {
	int maxsize;
	int dw, dh;
	std::list<VData*> free;
	std::mutex lock;
	MemPool(int n,int w,int h):maxsize(n),dw(w),dh(h){}
	VData* Get() {
		std::unique_lock<std::mutex> lk(lock);
		if (free.size() > 0) {
			auto ret= free.front();
			free.pop_front();
			return ret;
		}
		return new VData(dw, dh);
	}
	void Put(VData* ptr) {
		lock.lock();
		if (free.size() > maxsize) {
			lock.unlock();
			ptr->Close();
			return;
		}
		free.push_back(ptr);
		lock.unlock();
	}

	void Close() {
		std::unique_lock<std::mutex> lk(lock);
		maxsize = 0;
		for (auto i : free) {
			i->Close();
		}
		free.clear();

	}
	~MemPool() {
		if (maxsize || free.size()) {
			Close();
		}
	}

};

class Mpeg {
private:
	int vidx = -1, aidx = -1;
	int dw = -1, dh = -1;
	uint8_t* data[4];
	int             linesize[4];
	AVStream* vstream = NULL, * astream = NULL;
	AVCodecContext* ctx = NULL;
	const char* src = NULL;
	AVFormatContext* fctx = NULL;
	AVPacket* packet = NULL;
	AVFrame* frame = NULL;
	SwsContext* sws_ctx = NULL;
	AVDictionary* copts = NULL;
	AVDictionary* opts = NULL;
	std::shared_ptr<MemPool> pool;
	std::shared_mutex rwlock;
	bool quit = false;
	std::atomic<bool> exist=false;

public:
	Mpeg(const std::string& path, int dw, int dh) :src(path.c_str()), dw(dw), dh(dh){
	}
	Mpeg(const Mpeg&) = delete;
	void operator=(const Mpeg&) = delete;
	bool prepare();
	void doTask(moodycamel::BlockingReaderWriterCircularBuffer<VData*>& );
	void setPool(std::shared_ptr<MemPool> p) {
		pool = p;
	}
	bool getStates();
	~Mpeg() {
		if (fctx) {
			avformat_close_input(&fctx);
		}
		if (ctx) {
			avcodec_free_context(&ctx);
		}
		if (packet) {
			av_packet_unref(packet);
			av_packet_free(&packet);

		}
		if (frame) {
			av_frame_unref(frame);
			av_frame_free(&frame);
			frame = NULL;
		}
		if (sws_ctx) {
			sws_freeContext(sws_ctx);
			sws_ctx = NULL;
		}
		if (opts) {
			av_dict_free(&opts);
			opts = NULL;
		}

		if (copts) {
			av_dict_free(&copts);
			copts = NULL;
		}

	}
	int getW() {
		return dw;
	}
	void setQuit() {
		std::unique_lock<std::shared_mutex> lck(rwlock);
		quit = true;
	}
	int getH() {
		return dh;
	}
};